// 正则库
var regulars = {
    year: {
        regExp: /^(19|20)\d{2}$/,
        message: "只能为年份(四位,1900-2099)"
    },
    number: {
        regExp: /^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$/,
        message: "只能为数字"
    },
    bankNum: {
        regExp: /^\d{16}|\d{19}$/,
        message: "格式错误"
    },
    telephone: {
        regExp: /^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$/,
        message: "格式错误"
    },
    int: {
        regExp: /^[0-9]*$/,
        message: "只能为正整数"
    },
    phone: {
        regExp: /^[1][0-9]{10}$/,
        message: "格式错误"
    },
    allChinese: {
        regExp: /^([\u4E00-\u9FA5]+，?)+$/,
        message: "只能为中文"
    },
    haveChinese: {
        regExp: "[\\u4E00-\\u9FFF]+",
        message: "中含有汉字"
    },
    idCard15: {
        regExp: /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/,
        message: "格式错误"
    },
    idCard18: {
        regExp: /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$/,
        message: "格式错误"
    },
    url: {
        regExp: /^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+/,
        message: "格式错误"
    },
    email: {
        regExp: /^[-_A-Za-z0-9]+@([_A-Za-z0-9]+\.)+[A-Za-z0-9]{2,3}$/,
        message: "格式错误"
    },
    Special: {
        regExp: ["~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "{", "}", "[", "]", "(", ")", ":", ";", "'", "|", "\\", "<", ">", "?", "/", "<<", ">>", "||", "//", "administrators", "administrator", "管理员", "系统管理员", "admin", "select", "delete", "update", "insert", "create", "drop", "alter", "trancate"],
        message: "不能包含特殊字符"
    },
    null: {
        regExp: "^[ ]+$",
        message: "不能为空"
    },
};

// 判断对象是否完全一致
const isEqual = function (a, b) {
    if (a === b) {
        return a !== 0 || 1 / a === 1 / b;
    };
    if (a == null || b == null) {
        return a === b;
    };
    var A = Object.prototype.toString.call(a);
    var B = Object.prototype.toString.call(b);
    if (A !== B) {
        return false;
    };
    switch (A) {
        case '[object RegExp]':
        case '[object String]':
            return '' + a === '' + b;
        case '[object Number]':
            if (+a !== +a) {
                return +b !== +b;
            };
            return +a === 0 ? 1 / +a === 1 / b : +a === +b;
        case '[object Date]':
        case '[object Boolean]':
            return +a === +b;
    };
    if (A == '[object Object]') {
        if (JSON.stringify(a) != JSON.stringify(b)) {
            return false;
        };
        return true;
    };
    if (A == '[object Array]') {
        if (a.toString() == b.toString()) {
            return true;
        }
        return false;
    };
};

// 判断是否在数组中，（脱离jquery）
const inArray = function (str, _array) {
    let isInArray = -1;
    for (let i = 0; i < _array.length; i++) {
        const element = _array[i];
        if (isEqual(element, str)) {
            isInArray = i;
            break;
        };
    };
    return isInArray;
};

// 获取对象key值列表
const getKeyArray = function (obj) {
    var _array = [];
    eachObject(obj, function (item, key) {
        _array.push(key);
    });
    return _array;
};

// 历遍对象，并执行方法
const eachObject = function (obj, callback) {
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            const element = obj[key];
            var value = callback(element, key);
            if (value === false) {
                break;
            };
        }
    };
};

function test(type, str) {
    var re = new RegExp(regulars[type].regExp);
    return !re.test(str) ? true : false;
};

// 验证用方法集合
var verifyObj = {
    year: {
        event: value => { return test('year', value) },
        message: regulars.year.message,
    },
    number: {
        event: value => { return test('number', value) },
        message: regulars.number.message
    },
    bankNum: {
        event: value => { return test('bankNum', value) },
        message: regulars.bankNum.message
    },
    telephone: {
        event: value => { return test('telephone', value) },
        message: regulars.telephone.message
    },
    int: {
        event: value => { return test('int', value) },
        message: regulars.int.message
    },
    phone: {
        event: value => { return test('phone', value) },
        message: regulars.phone.message
    },
    url: {
        event: value => { return test('url', value) },
        message: regulars.url.message
    },
    email: {
        event: value => { return test('email', value) },
        message: regulars.email.message
    },
    allChinese: {
        event: value => { return test('allChinese', value) },
        message: regulars.allChinese.message
    },
    haveChinese: {
        event: function (str) {
            var re = new RegExp(regulars.haveChinese.regExp);
            return re.test(str) ? true : false;
        },
        message: regulars.haveChinese.message
    },
    notNull: {
        event: function (str) {
            if (str == "" || str == undefined || str == null || str == NaN) return !false;
            var re = new RegExp(regulars.null.regExp);
            return re.test(str);
        },
        message: regulars.null.message
    },
    isSpecial: {
        event: function (str) {
            str = str.toLowerCase();
            for (var i = 0; i < regulars.Special.regExp.length; i++) {
                if (str.indexOf(regulars.Special.regExp[i]) >= 0) {
                    return false;
                }
            }
            return true;
        },
        message: regulars.Special.message
    },
    isIdCard: {
        event: function (str) {
            var re1 = new RegExp(regulars.idCard15.regExp);
            var re2 = new RegExp(regulars.idCard18.regExp);
            return !(re1.test(str) || re2.test(str) ? true : false);
        },
        message: regulars.idCard18.message
    }
};

// 判断变量是否为某一值
const is = function (obj, type) {
    if (type) {
        var result = null;
        var objectString = Object.prototype.toString.call(obj);
        switch (type) {
            case "string":
                result = objectString == "[object String]";
                break;
            case "function":
                result = objectString == "[object Function]";
                break;
            case "array":
                result = objectString == "[object Array]";
                break;
            case "number":
                result = objectString == "[object Number]" && obj === obj;
                break;
            case "date":
                result = objectString == "[object Date]";
                break;
            case "object":
                result = objectString == "[object Object]";
                break;
            case "bool":
                result = objectString == "[object Boolean]";
                break;
            case "regExp":
                result = objectString == "[object RegExp]";
                break;
            case "null":
                result = objectString == "[object Null]";
                break;
            case "undefined":
                result = objectString == "[object Undefined]";
                break;
            case "NaN":
                result = (obj !== obj);
                break;
        };
        return result;
    } else {
        var mold = null;
        var objectString = Object.prototype.toString.call(obj);
        switch (objectString) {
            case "[object String]":
                mold = "string";
                break;
            case "[object Function]":
                mold = "function";
                break;
            case "[object Array]":
                mold = "array";
                break;
            case "[object Number]":
                if (obj !== obj) {
                    mold = "NaN";
                } else {
                    mold = "number"
                };
                break;
            case "[object Date]":
                mold = "date";
                break;
            case "[object Object]":
                mold = "object";
                break;
            case "[object Boolean]":
                mold = "bool";
                break;
            case "[object RegExp]":
                mold = "regExp";
                break;
            case "[object Null]":
                mold = "null";
                break;
            case "[object Undefined]":
                mold = "undefined";
                break;
        };
        return mold;
    };
};

const customLength = function (type, str) {
    var name = type.split('$');
    var length = str.toString().length;
    var nums = parseInt(name[1]);
    if (name[0] == 'les') {
        return !(length > nums) ? '不能小于' + nums + '位' : false;
    } else if (name[0] == 'gre') {
        var nums = parseInt(name[1]);
        return !(length <= nums) ? '不能大于' + nums + '位' : false;
    } else {
        console.error('error => 未找到验证规则:' + type);
    };
};

// 正则验证方法
const jude = function (value, type) {
    var keyArray = getKeyArray(verifyObj);
    if (type.indexOf('$') != -1) {
        return customLength(type, value);
    } else if (inArray(type, keyArray) != -1) {
        var answer = verifyObj[type].event(value);
        return answer ? verifyObj[type].message : false;
    } else {
        console.error('error => 未找到验证规则:' + type);
    };
};

const verifyRule = function (singleRule, value, text) {
    // 返回对象类型
    var ruleType = is(singleRule);
    if (ruleType == 'string') {
        // 当为String类型时,去默认验证方法中寻找
        var result = jude(value, singleRule);
        if (result) {
            return text + result;
        } else {
            return false;
        };
    } else if (ruleType == 'function') {
        // 当为方法类型时,执行方法,并返回验证 (方法通过,返回false,否则返回错误语句);
        var result = singleRule(value);
        if (result) {
            return result;
        } else {
            return false;
        };
    } else if (ruleType == 'object' && singleRule.regExp && is(singleRule.regExp, 'regExp')) {
        // 当对象方法为正则表达式时,直接使用正则表达式进行判断
        var errorText = singleRule.errorText;
        var regular = singleRule.regExp;
        var re = new RegExp(regular);
        if (re.test(value)) {
            return false;
        } else {
            return errorText;
        };
    } else {
        // 其他类型直接跳过,控制台输出错误信息
        console.error('rule模块 : 未识别的判断类型');
        return false;
    };
};

const rules = function (rulesObj, value) {
    var text = rulesObj.text;
    var rulesArray = rulesObj.rules;
    if (!rulesArray) {
        return false;
    };
    // 判断是否为数组
    if (is(rulesArray, 'array')) {
        // 跳过非空验证
        // if ($.inArray("notNull", rulesArray) == -1 && (value == '' || value === null)) {
        //     return false;
        // };
        // 进行循环验证
        var _text = false;
        for (var i = 0; i < rulesArray.length; i++) {
            var element = rulesArray[i];
            var result = verifyRule(element, value, text);
            if (result) {
                _text = result;
                break;
            };
        };
        if (_text) {
            return _text;
        } else {
            return false;
        };
    } else if (is(rulesArray, 'string')) {
        // 进行单条验证
        var result = verifyRule(rulesArray, value, text);
        if (result) {
            return result;
        } else {
            return false;
        };
    } else if (is(rulesArray, 'function')) {
        // 进行单条验证
        var result = verifyRule(rulesArray, value, text);
        if (result) {
            return result;
        } else {
            return false;
        };
    }
};